﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace RPGServer.Contracts.Requests
{
    class RequestSwitchMap
    {
        /// <summary>
        /// 处理切换地图操作
        /// </summary>
        public static void Process(RPGPlayer player, byte[] buffer, int length)
        {
            int offset = 2;
            byte triggerType = IntUtil.ByteFromBuffer(buffer, offset, out offset);
            // 单位编号
            uint objectId = IntUtil.UIntFromBuffer(buffer, offset, out offset);
            // 当前地图编号
            ushort curMapId = IntUtil.UShortFromBuffer(buffer, offset, out offset);
            // 当前位置-行
            ushort curPosRow = IntUtil.UShortFromBuffer(buffer, offset, out offset);
            // 当前位置-列
            ushort curPosCol = IntUtil.UShortFromBuffer(buffer, offset, out offset);
            // 目标地图编号
            ushort targetMapId = IntUtil.UShortFromBuffer(buffer, offset, out offset);

            Log.Debug("request", "玩家({0})请求切换地图[object:{1} map:{2} pos:({3},{4}) targetMap:{4}]",
                player.Id,
                objectId,
                curMapId,
                curPosRow,
                curPosCol,
                targetMapId);

            if (triggerType == RPGNET_TRIGGERTYPE_SWITCH_MAP.ENTER_GAME)
            {
                player.RoleId = objectId;
                player.CurMapId = targetMapId;
                player.CurPosRow = curPosRow;
                player.CurPosCol = curPosCol;

                byte[] data = new byte[255];
                offset = 0;
                // scenario
                IntUtil.ByteToBuffer(RPGNET_SCENARIO.GAME, data, offset, out offset);
                // command
                IntUtil.ByteToBuffer(RPGNET_RESPONSE.SWITH_MAP, data, offset, out offset);
                // error code
                IntUtil.ByteToBuffer(RPGNET_RESPONSE_ERROR.NOERROR, data, offset, out offset);
                // map id
                IntUtil.UShortToBuffer(player.CurMapId, data, offset, out offset);
                // pos row
                IntUtil.UShortToBuffer(player.CurPosRow, data, offset, out offset);
                // pos col
                IntUtil.UShortToBuffer(player.CurPosCol, data, offset, out offset);
                // object direction
                IntUtil.ByteToBuffer(0x00, data, offset, out offset);

                player.Client.SendData(data, offset);

                Log.Debug("response", "玩家({0})切换地图成功:地图编号({1})", player.Client.GetNetAddress(), targetMapId);

                #region 玩家是进入游戏时的切换地图，直接附加到目标地图上
                // 玩家在这个时候确定了一个角色，更新内存中玩家的角色模型编号
                player.RoleModelId = 8001;

                RPGMapPlayerCollection toMap = CacheData.GetInstance().GetMap(targetMapId);
                CacheData.GetInstance().AddPlayerToMap(toMap, player);
                #endregion

                NotifyPlayerEnterMap(toMap, player);
            }
            else
            {
                RPGSwitchPoint sp = CacheData.GetInstance().CacheMapService.GetSwitchPoint(curMapId, curPosRow, curPosCol, targetMapId);
                if (sp != null)
                {
                    player.RoleId = objectId;
                    player.CurMapId = targetMapId;
                    player.CurPosRow = sp.ToPosRow;
                    player.CurPosCol = sp.ToPosCol;
                    
                    byte[] data = new byte[255];
                    offset = 0;
                    // scenario
                    IntUtil.ByteToBuffer(RPGNET_SCENARIO.GAME, data, offset, out offset);
                    // command
                    IntUtil.ByteToBuffer(RPGNET_RESPONSE.SWITH_MAP, data, offset, out offset);
                    // error code
                    IntUtil.ByteToBuffer(RPGNET_RESPONSE_ERROR.NOERROR, data, offset, out offset);
                    // map id
                    IntUtil.UShortToBuffer(player.CurMapId, data, offset, out offset);
                    // pos row
                    IntUtil.UShortToBuffer(player.CurPosRow, data, offset, out offset);
                    // pos col
                    IntUtil.UShortToBuffer(player.CurPosCol, data, offset, out offset);
                    // object direction
                    IntUtil.ByteToBuffer(0x00, data, offset, out offset);

                    player.Client.SendData(data, offset);

                    Log.Debug("response", "玩家({0})切换地图成功:地图编号({1})", player.Client.GetNetAddress(), targetMapId);

                    #region 玩家进去地图切换点要求切换地图，从当前地图附加到目标地图上
                    RPGMapPlayerCollection fromMap = CacheData.GetInstance().GetMap(curMapId);
                    RPGMapPlayerCollection toMap = CacheData.GetInstance().GetMap(targetMapId);
                    CacheData.GetInstance().MovePlayerToMap(fromMap, toMap, player);
                    #endregion

                    NotifyPlayerLeaveMap(fromMap, player);
                    NotifyPlayerEnterMap(toMap, player);
                }
                else
                {
                    // 切换失败，回到源地图
                    byte[] data = new byte[255];
                    offset = 0;
                    // scenario
                    IntUtil.ByteToBuffer(RPGNET_SCENARIO.GAME, data, offset, out offset);
                    // command
                    IntUtil.ByteToBuffer(RPGNET_RESPONSE.SWITH_MAP, data, offset, out offset);
                    // error code
                    IntUtil.ByteToBuffer(RPGNET_RESPONSE_ERROR.UNKNOWN, data, offset, out offset);

                    player.Client.SendData(data, offset);
                    Log.Error("response", "玩家({0})切换地图失败:地图编号({1})", player.Client.GetNetAddress(), targetMapId);
                }
            }
        }

        /// <summary>
        /// 通知目标地图上的玩家，有人进入此地图
        /// </summary>
        /// <param name="map"></param>
        /// <param name="player"></param>
        private static void NotifyPlayerEnterMap(RPGMapPlayerCollection map, RPGPlayer player)
        {
            byte[] data = new byte[255];
            int offset = 0;
            // scenario
            IntUtil.ByteToBuffer(RPGNET_SCENARIO.SER_MSG, data, offset, out offset);
            // command
            IntUtil.ByteToBuffer(RPGNET_MESSAGE.ADD_OBJECT, data, offset, out offset);
            // player id
            IntUtil.UIntToBuffer(player.Id, data, offset, out offset);
            // object id
            IntUtil.UIntToBuffer(player.RoleId, data, offset, out offset);
            // object name
            IntUtil.StringToBuffer(String.Format("object{0}", player.RoleId), data, offset, 16, out offset);
            // object model id
            IntUtil.UIntToBuffer(player.RoleModelId, data, offset, out offset);
            // object level
            IntUtil.ByteToBuffer(0x01, data, offset, out offset);
            // map id
            IntUtil.UShortToBuffer(player.CurMapId, data, offset, out offset);
            // pos row
            IntUtil.UShortToBuffer(player.CurPosRow, data, offset, out offset);
            // pos col
            IntUtil.UShortToBuffer(player.CurPosCol, data, offset, out offset);
            // object direction
            IntUtil.ByteToBuffer(0x00, data, offset, out offset);

            for (int index = 0; index < map.PlayerList.Count; index++)
            {
                RPGPlayer oPlayer = map.PlayerList[index];
                if (oPlayer != null && oPlayer.Id != player.Id)
                {
                    oPlayer.Client.SendData(data, offset);
                }
            }
        }

        /// <summary>
        /// 通知地图上的玩家有人离开此地图
        /// </summary>
        /// <param name="map"></param>
        /// <param name="player"></param>
        private static void NotifyPlayerLeaveMap(RPGMapPlayerCollection map, RPGPlayer player)
        {
            byte[] data = new byte[255];
            int offset = 0;
            // scenario
            IntUtil.ByteToBuffer(RPGNET_SCENARIO.GAME, data, offset, out offset);
            // command
            IntUtil.ByteToBuffer(RPGNET_MESSAGE.REMOVE_OBJECT, data, offset, out offset);
            // player id
            IntUtil.UIntToBuffer(player.Id, data, offset, out offset);
            // object id
            IntUtil.UIntToBuffer(player.RoleId, data, offset, out offset);
            // map id
            IntUtil.UIntToBuffer(player.CurMapId, data, offset, out offset);
            // pos row
            IntUtil.UShortToBuffer(player.CurPosRow, data, offset, out offset);
            // pos col
            IntUtil.UShortToBuffer(player.CurPosCol, data, offset, out offset);
            // object direction
            IntUtil.ByteToBuffer(0x00, data, offset, out offset);

            for (int index = 0; index < map.PlayerList.Count; index++)
            {
                RPGPlayer oPlayer = map.PlayerList[index];
                if (oPlayer != null && oPlayer.Id != player.Id)
                {
                    oPlayer.Client.SendData(data, offset);
                }
            }
        }
    }
}
